speciesrangeR - species range maps in R

This repository holds a package with several skeleton functions to retrieve data from online repositories, and to create species range maps. This repo serves as a proof of concept for GSoC 2018 proposal.

To install the package run:

devtools::install_github("mirzacengic/speciesrangeR")

Tasks to solve:

  • Easy: write a script to download occurrence data from GBIF for a species and display them on a map.
  • Medium: Draw a convex hull polygon around the points in the earlier test.
  • Hard: Clip the polygon you generated in medium test to world map (Keep only part of the polygon which is on land).
  • Bonus: Get extent of suitable habitat within the range.

Let’s load the necessary packages. This should eventually go to the package namespace, right now all libraries have to be loaded.

if(!require(pacman, quietly = TRUE))
{
  install.packages("pacman")
}
if(!require(speciesrangeR, quietly = TRUE))
{
  pacman::p_install_gh("mirzacengic/speciesrangeR")
}
pacman::p_load(spocc, sf, mapview, lubridate, dplyr, raster, tictoc,
               sf, scrubr, stringr, sp, rgeos, dismo, broom, tmap)

Working with speciesrangeR

We will load here speciesrangeR package. Use get_species_data() to query data from the Global Biodiversity Information Facility - GBIF. Function is a wrapper around occ() function from spocc package.

# Load package 
library(speciesrangeR)
# Get gbif data for Salamandra atra for Italy, with cleaned output coordinates.
sal_atra_ita <- get_species_data("Salamandra atra", return_clean = TRUE, 
                                 return = "sp", country = "ITA")

Get occurence data from GBIF

Here we will retrieve species occurence data for species Salamandra atra Laurenti, 1768. Function get_species_data() can take country argument, so we will query for data for Italy. Default limit of spocc::occ() function is 500 points, however you can pass a numeric value to the limit argument. Country data is filtered afterwards, therefore the number of points does not have to correspond to limit. Additional arguments can be passed to the spocc::occ() function by using .... Use ?get_species_data and ?spocc::occto see the documentation of both functions for more details.

We will preview retrieved species data.

# Plot data
mapview(sal_atra_ita)

One point is in Torino and is clearly wrong datapoint. Most likely the point is assigned to an instution where the specimen is storaged.

# Plot the most easterly point 
mapview(sal_atra_ita[which.min(sal_atra_ita@coords), ])

Function get_species_data() has argument return_clean which uses scrubr package to clean wrong data. According to the documentation of scrubr package, removing of these cases is on a feature list to be implemented, but now we will remove the wrong point manually.

# Remove the most easterly point.
sal_atra_ita_clean <- sal_atra_ita[-which.min(sal_atra_ita@coords), ]

Let’s plot the data again.

mapview(sal_atra_ita_clean)

On the first look it looks better. Now we will calculate the extent of occurence (EOO).


Extent of occurence

Extent of occurence is calculated using minimum convex hull from the rgeos package. Function can return simple feature or spatial points dataframe. In the future more methods of calculating bounding polygons should be added (eg. concave hull).

# Get EOO
sal_atra_eoo <- get_eoo(sal_atra_ita_clean, return = "sp")

Plotting the extent of occurence.

mapview(sal_atra_eoo)

Extent of suitable habitat

In this part, we will extract extent of suitable habitat by filtering extent of occurence (EOO) within min-max values of a raster variable. In the future multiple rasters + categorical variables should be added as filtering variable. Add later custom cutoff values and function passing instead of min/max.

# Load SRTM raster for North Italy (resampled to ~2 kilometer resolution for faster code execution)
srtm_italy <- raster("Y:/Mirza_Cengic/Projects/Other/GSoC/srtm_39_03_1.tif")

# Might take time with fine cell rasters
sal_atra_esh <- get_esh(species_data = sal_atra_ita_clean, 
                        species_eoo = sal_atra_eoo,
                        habitat_variable = srtm_italy)

Let’s plot the extent of suitable habitat with the overlaid points used for creating ESH.

mapview(sal_atra_esh)

Extent of suitable habitat with filtered elevation values. NOTE - There are some errors in the overlap of point due to raster aggregation.

LS0tDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQo8IS0tIFJFQURNRS5tZCBpcyBnZW5lcmF0ZWQgZnJvbSBSRUFETUUuUm1kLiBQbGVhc2UgZWRpdCB0aGF0IGZpbGUgLS0+DQo8IS0tIG91dHB1dDogcm1hcmtkb3duOjpnaXRodWJfZG9jdW1lbnQgLS0+DQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGZpZy5wYXRoID0gIlJFQURNRV9maWd1cmVzLyIpDQpgYGANCg0KIyBzcGVjaWVzcmFuZ2VSIC0gc3BlY2llcyByYW5nZSBtYXBzIGluIFINCg0KVGhpcyByZXBvc2l0b3J5IGhvbGRzIGEgcGFja2FnZSB3aXRoIHNldmVyYWwgc2tlbGV0b24gZnVuY3Rpb25zIHRvIHJldHJpZXZlIGRhdGEgZnJvbSBvbmxpbmUgcmVwb3NpdG9yaWVzLCBhbmQgdG8gY3JlYXRlIHNwZWNpZXMgcmFuZ2UgbWFwcy4NClRoaXMgcmVwbyBzZXJ2ZXMgYXMgYSAqKnByb29mIG9mIGNvbmNlcHQqKiBmb3IgW0dTb0MgMjAxOCBwcm9wb3NhbF0oaHR0cHM6Ly9naXRodWIuY29tL3JzdGF0cy1nc29jL2dzb2MyMDE4L3dpa2kvU3BlY2llcy1yYW5nZS1tYXBzLWluLVIpLg0KDQpUbyBpbnN0YWxsIHRoZSBwYWNrYWdlIHJ1bjoNCmBgYHtyLCBldmFsID0gRkFMU0UsIGVjaG8gPSBUUlVFfQ0KZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJtaXJ6YWNlbmdpYy9zcGVjaWVzcmFuZ2VSIikNCmBgYA0KDQojIyMjIFRhc2tzIHRvIHNvbHZlOiAgDQotIEVhc3k6IHdyaXRlIGEgc2NyaXB0IHRvIGRvd25sb2FkIG9jY3VycmVuY2UgZGF0YSBmcm9tIEdCSUYgZm9yIGEgc3BlY2llcyBhbmQNCmRpc3BsYXkgdGhlbSBvbiBhIG1hcC4gIA0KLSBNZWRpdW06IERyYXcgYSBjb252ZXggaHVsbCBwb2x5Z29uIGFyb3VuZCB0aGUgcG9pbnRzIGluIHRoZSBlYXJsaWVyIHRlc3QuICANCi0gSGFyZDogQ2xpcCB0aGUgcG9seWdvbiB5b3UgZ2VuZXJhdGVkIGluIG1lZGl1bSB0ZXN0IHRvIHdvcmxkDQptYXAgKEtlZXAgb25seSBwYXJ0IG9mIHRoZSBwb2x5Z29uIHdoaWNoIGlzIG9uIGxhbmQpLiAgDQotIEJvbnVzOiBHZXQgZXh0ZW50IG9mIHN1aXRhYmxlIGhhYml0YXQgd2l0aGluIHRoZSByYW5nZS4NCg0KDQpMZXQncyBsb2FkIHRoZSBuZWNlc3NhcnkgcGFja2FnZXMuIFRoaXMgc2hvdWxkIGV2ZW50dWFsbHkgZ28gdG8gdGhlIHBhY2thZ2UgbmFtZXNwYWNlLCByaWdodCBub3cgYWxsIGxpYnJhcmllcyBoYXZlIHRvIGJlIGxvYWRlZC4NCmBgYHtyIHNjcmlwdF9zZXR1cCwgZWNobz1UUlVFLCByZXN1bHRzID0gImhpZGUifQ0KaWYoIXJlcXVpcmUocGFjbWFuLCBxdWlldGx5ID0gVFJVRSkpDQp7DQogIGluc3RhbGwucGFja2FnZXMoInBhY21hbiIpDQp9DQppZighcmVxdWlyZShzcGVjaWVzcmFuZ2VSLCBxdWlldGx5ID0gVFJVRSkpDQp7DQogIHBhY21hbjo6cF9pbnN0YWxsX2doKCJtaXJ6YWNlbmdpYy9zcGVjaWVzcmFuZ2VSIikNCn0NCnBhY21hbjo6cF9sb2FkKHNwb2NjLCBzZiwgbWFwdmlldywgbHVicmlkYXRlLCBkcGx5ciwgcmFzdGVyLCB0aWN0b2MsDQogICAgICAgICAgICAgICBzZiwgc2NydWJyLCBzdHJpbmdyLCBzcCwgcmdlb3MsIGRpc21vLCBicm9vbSwgdG1hcCkNCg0KDQpgYGANCg0KDQojIyBXb3JraW5nIHdpdGggc3BlY2llc3JhbmdlUg0KV2Ugd2lsbCBsb2FkIGhlcmUgc3BlY2llc3JhbmdlUiBwYWNrYWdlLiBVc2UgYGdldF9zcGVjaWVzX2RhdGEoKWAgdG8gcXVlcnkgZGF0YSBmcm9tIHRoZSBbR2xvYmFsIEJpb2RpdmVyc2l0eSBJbmZvcm1hdGlvbiBGYWNpbGl0eSAtIEdCSUZdKGh0dHBzOi8vd3d3LmdiaWYub3JnLykuIEZ1bmN0aW9uIGlzIGEgd3JhcHBlciBhcm91bmQgW2BvY2MoKWBdKGh0dHBzOi8vd3d3LnJkb2N1bWVudGF0aW9uLm9yZy9wYWNrYWdlcy9zcG9jYy92ZXJzaW9ucy8wLjcuMC90b3BpY3Mvb2NjKSBmdW5jdGlvbiBmcm9tIFtzcG9jY10oaHR0cHM6Ly9yb3BlbnNjaS5naXRodWIuaW8vc3BvY2MvKSBwYWNrYWdlLg0KDQpgYGB7ciBzcF9kYXRhLCBlY2hvPVRSVUV9DQoNCiMgTG9hZCBwYWNrYWdlIA0KbGlicmFyeShzcGVjaWVzcmFuZ2VSKQ0KDQojIEdldCBnYmlmIGRhdGEgZm9yIFNhbGFtYW5kcmEgYXRyYSBmb3IgSXRhbHksIHdpdGggY2xlYW5lZCBvdXRwdXQgY29vcmRpbmF0ZXMuDQpzYWxfYXRyYV9pdGEgPC0gZ2V0X3NwZWNpZXNfZGF0YSgiU2FsYW1hbmRyYSBhdHJhIiwgcmV0dXJuX2NsZWFuID0gVFJVRSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gPSAic3AiLCBjb3VudHJ5ID0gIklUQSIpDQpgYGANCg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCnAxIDwtIG1hcHZpZXcoc2FsX2F0cmFfaXRhKQ0KcDENCm1hcHNob3QocDEsIGZpbGUgPSAibWFwMS5wbmciKQ0KYGBgDQoNCi0tLQ0KDQojIyBHZXQgb2NjdXJlbmNlIGRhdGEgZnJvbSBHQklGDQpIZXJlIHdlIHdpbGwgcmV0cmlldmUgc3BlY2llcyBvY2N1cmVuY2UgZGF0YSBmb3Igc3BlY2llcyBbKlNhbGFtYW5kcmEgYXRyYSogTGF1cmVudGksIDE3NjhdKGh0dHBzOi8vd3d3LmdiaWYub3JnL3NwZWNpZXMvMjQzMTc4MSkuIEZ1bmN0aW9uIGBnZXRfc3BlY2llc19kYXRhKClgIGNhbiB0YWtlIGNvdW50cnkgYXJndW1lbnQsIHNvIHdlIHdpbGwgcXVlcnkgZm9yIGRhdGEgZm9yIEl0YWx5LiBEZWZhdWx0IGxpbWl0IG9mIGBzcG9jYzo6b2NjKClgIGZ1bmN0aW9uIGlzIDUwMCBwb2ludHMsIGhvd2V2ZXIgeW91IGNhbiBwYXNzIGEgbnVtZXJpYyB2YWx1ZSB0byB0aGUgYGBsaW1pdGBgIGFyZ3VtZW50LiBDb3VudHJ5IGRhdGEgaXMgZmlsdGVyZWQgYWZ0ZXJ3YXJkcywgdGhlcmVmb3JlIHRoZSBudW1iZXIgb2YgcG9pbnRzIGRvZXMgbm90IGhhdmUgdG8gY29ycmVzcG9uZCB0byBsaW1pdC4gQWRkaXRpb25hbCBhcmd1bWVudHMgY2FuIGJlIHBhc3NlZCB0byB0aGUgYHNwb2NjOjpvY2MoKWAgZnVuY3Rpb24gYnkgdXNpbmcgYC4uLmAuIFVzZSBgP2dldF9zcGVjaWVzX2RhdGFgIGFuZCBgP3Nwb2NjOjpvY2NgdG8gc2VlIHRoZSBkb2N1bWVudGF0aW9uIG9mIGJvdGggZnVuY3Rpb25zIGZvciBtb3JlIGRldGFpbHMuIA0KDQpXZSB3aWxsIHByZXZpZXcgcmV0cmlldmVkIHNwZWNpZXMgZGF0YS4NCg0KYGBge3IgY3JlYXRlX21hcDEsIGV2YWwgPSBGQUxTRSwgZWNobyA9IFRSVUV9DQoNCiMgUGxvdCBkYXRhDQptYXB2aWV3KHNhbF9hdHJhX2l0YSkNCmBgYA0KIVtdKG1hcDEucG5nKSAgDQoNCk9uZSBwb2ludCBpcyBpbiBUb3Jpbm8gYW5kIGlzIGNsZWFybHkgd3JvbmcgZGF0YXBvaW50LiBNb3N0IGxpa2VseSB0aGUgcG9pbnQgaXMgYXNzaWduZWQgdG8gYW4gaW5zdHV0aW9uIHdoZXJlIHRoZSBzcGVjaW1lbiBpcyBzdG9yYWdlZC4gDQpgYGB7ciBtYXBfdG9yaW5vLCBpbmNsdWRlID0gRkFMU0V9DQoNCnAyIDwtIG1hcHZpZXcoc2FsX2F0cmFfaXRhW3doaWNoLm1pbihzYWxfYXRyYV9pdGFAY29vcmRzKSwgXSkNCm1hcHNob3QocDIsIGZpbGUgPSAibWFwMi5wbmciKQ0KDQpgYGANCg0KYGBge3IgY3JlYXRlX21hcDIsIGV2YWwgPSBGQUxTRSwgZWNobyA9IFRSVUV9DQojIFBsb3QgdGhlIG1vc3QgZWFzdGVybHkgcG9pbnQgDQptYXB2aWV3KHNhbF9hdHJhX2l0YVt3aGljaC5taW4oc2FsX2F0cmFfaXRhQGNvb3JkcyksIF0pDQpgYGANCiFbXShtYXAyLnBuZykNCg0KDQpGdW5jdGlvbiBgZ2V0X3NwZWNpZXNfZGF0YSgpYCBoYXMgYXJndW1lbnQgcmV0dXJuX2NsZWFuIHdoaWNoIHVzZXMgW2BzY3J1YnJgXShodHRwczovL2dpdGh1Yi5jb20vcm9wZW5zY2kvc2NydWJyKSBwYWNrYWdlIHRvIGNsZWFuIHdyb25nIGRhdGEuIEFjY29yZGluZyB0byB0aGUgZG9jdW1lbnRhdGlvbiBvZiBzY3J1YnIgcGFja2FnZSwgcmVtb3Zpbmcgb2YgdGhlc2UgY2FzZXMgaXMgb24gYSBmZWF0dXJlIGxpc3QgdG8gYmUgaW1wbGVtZW50ZWQsIGJ1dCBub3cgd2Ugd2lsbCByZW1vdmUgdGhlIHdyb25nIHBvaW50IG1hbnVhbGx5Lg0KDQpgYGB7ciBjbGVhbl9kYXRhLCBlY2hvPVRSVUV9DQojIFJlbW92ZSB0aGUgbW9zdCBlYXN0ZXJseSBwb2ludC4NCnNhbF9hdHJhX2l0YV9jbGVhbiA8LSBzYWxfYXRyYV9pdGFbLXdoaWNoLm1pbihzYWxfYXRyYV9pdGFAY29vcmRzKSwgXQ0KDQpgYGANCg0KDQpgYGB7ciBtYXBfY2xlYW5lZCwgaW5jbHVkZSA9IEZBTFNFfQ0KcDMgPC0gbWFwdmlldyhzYWxfYXRyYV9pdGFfY2xlYW4pDQptYXBzaG90KHAzLCBmaWxlID0gIm1hcDMucG5nIikNCg0KYGBgDQoNCkxldCdzIHBsb3QgdGhlIGRhdGEgYWdhaW4uICANCmBgYHtyIGNyZWF0ZV9tYXAzLCBldmFsID0gRkFMU0UsIGVjaG8gPSBUUlVFfQ0KbWFwdmlldyhzYWxfYXRyYV9pdGFfY2xlYW4pDQpgYGANCg0KIVtdKG1hcDMucG5nKSAgICANCiAgDQogIA0KT24gdGhlIGZpcnN0IGxvb2sgaXQgbG9va3MgYmV0dGVyLiBOb3cgd2Ugd2lsbCBjYWxjdWxhdGUgdGhlIGV4dGVudCBvZiBvY2N1cmVuY2UgKEVPTykuDQoNCi0tLQ0KDQojIyBFeHRlbnQgb2Ygb2NjdXJlbmNlDQoNCkV4dGVudCBvZiBvY2N1cmVuY2UgaXMgY2FsY3VsYXRlZCB1c2luZyBtaW5pbXVtIGNvbnZleCBodWxsIGZyb20gdGhlIGByZ2Vvc2AgcGFja2FnZS4gRnVuY3Rpb24gY2FuIHJldHVybiBzaW1wbGUgZmVhdHVyZSBvciBzcGF0aWFsIHBvaW50cyBkYXRhZnJhbWUuIEluIHRoZSBmdXR1cmUgbW9yZSBtZXRob2RzIG9mIGNhbGN1bGF0aW5nIGJvdW5kaW5nIHBvbHlnb25zIHNob3VsZCBiZSBhZGRlZCAoZWcuIGNvbmNhdmUgaHVsbCkuDQpgYGB7ciBnZXRfZW9vfQ0KIyBHZXQgRU9PDQpzYWxfYXRyYV9lb28gPC0gZ2V0X2VvbyhzYWxfYXRyYV9pdGFfY2xlYW4sIHJldHVybiA9ICJzcCIpDQoNCmBgYA0KDQpgYGB7ciBtYXBfZW9vLCBpbmNsdWRlID0gRkFMU0V9DQpwNCA8LSBtYXB2aWV3KHNhbF9hdHJhX2VvbykNCm1hcHNob3QocDQsIGZpbGUgPSAibWFwNC5wbmciKQ0KDQpgYGANCg0KUGxvdHRpbmcgdGhlIGV4dGVudCBvZiBvY2N1cmVuY2UuDQpgYGB7ciBjcmVhdGVfbWFwNCwgZXZhbCA9IEZBTFNFLCBlY2hvID0gVFJVRX0NCm1hcHZpZXcoc2FsX2F0cmFfZW9vKQ0KYGBgDQoNCiFbXShtYXA0LnBuZykNCg0KLS0tDQoNCiMjIEV4dGVudCBvZiBzdWl0YWJsZSBoYWJpdGF0IA0KDQpJbiB0aGlzIHBhcnQsIHdlIHdpbGwgZXh0cmFjdCBleHRlbnQgb2Ygc3VpdGFibGUgaGFiaXRhdCBieSBmaWx0ZXJpbmcgZXh0ZW50IG9mIG9jY3VyZW5jZSAoRU9PKSB3aXRoaW4gbWluLW1heCB2YWx1ZXMgb2YgYSByYXN0ZXIgdmFyaWFibGUuIEluIHRoZSBmdXR1cmUgbXVsdGlwbGUgcmFzdGVycyArIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyBzaG91bGQgYmUgYWRkZWQgYXMgZmlsdGVyaW5nIHZhcmlhYmxlLiBBZGQgbGF0ZXIgY3VzdG9tIGN1dG9mZiB2YWx1ZXMgYW5kIGZ1bmN0aW9uIHBhc3NpbmcgaW5zdGVhZCBvZiBtaW4vbWF4Lg0KDQoNCmBgYHtyIGdldF9lc2h9DQojIExvYWQgU1JUTSByYXN0ZXIgZm9yIE5vcnRoIEl0YWx5IChyZXNhbXBsZWQgdG8gfjIga2lsb21ldGVyIHJlc29sdXRpb24gZm9yIGZhc3RlciBjb2RlIGV4ZWN1dGlvbikNCnNydG1faXRhbHkgPC0gcmFzdGVyKCJZOi9NaXJ6YV9DZW5naWMvUHJvamVjdHMvT3RoZXIvR1NvQy9zcnRtXzM5XzAzXzEudGlmIikNCg0KIyBNaWdodCB0YWtlIHRpbWUgd2l0aCBmaW5lIGNlbGwgcmFzdGVycw0Kc2FsX2F0cmFfZXNoIDwtIGdldF9lc2goc3BlY2llc19kYXRhID0gc2FsX2F0cmFfaXRhX2NsZWFuLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHNwZWNpZXNfZW9vID0gc2FsX2F0cmFfZW9vLA0KICAgICAgICAgICAgICAgICAgICAgICAgaGFiaXRhdF92YXJpYWJsZSA9IHNydG1faXRhbHkpDQoNCg0KDQpgYGANCg0KYGBge3IgbWFwX2VzaCwgaW5jbHVkZSA9IEZBTFNFfQ0KcDUgPC0gbWFwdmlldyhzYWxfYXRyYV9lc2gsIG1hcC50eXBlcyA9ICJTdGFtZW4uVGVycmFpbkJhY2tncm91bmQiLCANCiAgICAgICAgICAgICAgYWxwaGEucmVnaW9ucyA9IDAuNSwgbHdkID0gMykgKyBtYXB2aWV3KHNhbF9hdHJhX2l0YV9jbGVhbiwgY29sLnJlZ2lvbnMgPSAicmVkIikNCg0KbWFwc2hvdChwNSwgZmlsZSA9ICJtYXA1LnBuZyIpDQoNCmBgYA0KDQpMZXQncyBwbG90IHRoZSBleHRlbnQgb2Ygc3VpdGFibGUgaGFiaXRhdCB3aXRoIHRoZSBvdmVybGFpZCBwb2ludHMgdXNlZCBmb3IgY3JlYXRpbmcgRVNILg0KYGBge3IgY3JlYXRlX21hcDUsIGV2YWwgPSBGQUxTRSwgZWNobyA9IFRSVUV9DQptYXB2aWV3KHNhbF9hdHJhX2VzaCkNCmBgYA0KDQpFeHRlbnQgb2Ygc3VpdGFibGUgaGFiaXRhdCB3aXRoIGZpbHRlcmVkIGVsZXZhdGlvbiB2YWx1ZXMuICoqTk9URSoqIC0gVGhlcmUgYXJlIHNvbWUgZXJyb3JzIGluIHRoZSBvdmVybGFwIG9mIHBvaW50IGR1ZSB0byByYXN0ZXIgYWdncmVnYXRpb24uDQohW10obWFwNS5wbmcpDQo=